package com.sl.ms.carriage.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.stream.StreamUtil;
import cn.hutool.core.util.*;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.sl.ms.base.api.common.AreaFeign;
import com.sl.ms.base.domain.base.AreaDto;
import com.sl.ms.carriage.domain.constant.CarriageConstant;
import com.sl.ms.carriage.domain.dto.CarriageDTO;
import com.sl.ms.carriage.domain.dto.WaybillDTO;
import com.sl.ms.carriage.domain.enums.EconomicRegionEnum;
import com.sl.ms.carriage.entity.CarriageEntity;
import com.sl.ms.carriage.enums.CarriageExceptionEnum;
import com.sl.ms.carriage.handler.CarriageChainHandler;
import com.sl.ms.carriage.mapper.CarriageMapper;
import com.sl.ms.carriage.service.CarriageService;
import com.sl.ms.carriage.utils.CarriageUtils;
import com.sl.transport.common.exception.SLException;
import org.jetbrains.annotations.NotNull;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class CarriageServiceImpl extends ServiceImpl<CarriageMapper, CarriageEntity> implements CarriageService {


    @Override
    public CarriageDTO saveOrUpdate(CarriageDTO carriageDto) {
        // 1. 根据条件查询模板
        // 3. 是否属于经济区互寄模板
        if (ObjectUtil.notEqual(carriageDto.getTemplateType(), CarriageConstant.ECONOMIC_ZONE)){
            CarriageEntity carriageEntity = this.findByTemplateType(carriageDto.getTemplateType());
            // 2. 判断模板是否存在，如果不存在  直接保存
            if (ObjectUtil.isEmpty(carriageEntity)) {
                // 直接保存
                return saveOrUpdateDto(carriageDto);
            }
            //  3.1 如果不是经济区，判断id是否为空
            if (ObjectUtil.isEmpty(carriageDto.getId())){
                throw new SLException(CarriageExceptionEnum.NOT_ECONOMIC_ZONE_REPEAT);
            }
            //  3.2 判断当前要修改的id 和 已存在的模板id是否相等
            if (ObjectUtil.notEqual(carriageDto.getId(),carriageEntity.getId())){
                throw new SLException(CarriageExceptionEnum.NOT_ECONOMIC_ZONE_REPEAT);
            }
            return saveOrUpdateDto(carriageDto);
        }
        // 4. 是经济区互寄模板，判断新的模板经济区 和 已存在的模板经济区id不能重复
        List<CarriageEntity> economicList = findByEconomicTemplateType();
        // List<String>    [4 , 5]
        // economicList CarriageEntity  2,3     4,5    ,切割    -->   [2,3,4,5]
        List<String> associatedCityList = economicList.stream() // List<模板>
                .map(CarriageEntity::getAssociatedCity) // 2,3     4,5
                .map(associatedCityStr -> StrUtil.split(associatedCityStr, ","))
                .flatMap(StreamUtil::of)
                .collect(Collectors.toList());

        Collection<String> intersection = CollUtil.intersection(associatedCityList, carriageDto.getAssociatedCityList());
        if (CollUtil.isNotEmpty(intersection)) {
            throw new SLException(CarriageExceptionEnum.ECONOMIC_ZONE_CITY_REPEAT);
        }
        return saveOrUpdateDto(carriageDto);
    }

    @NotNull
    private CarriageDTO saveOrUpdateDto(CarriageDTO carriageDto) {
        CarriageEntity entity = CarriageUtils.toEntity(carriageDto);
        this.saveOrUpdate(entity);
        return CarriageUtils.toDTO(entity);
    }

    @Override
    public List<CarriageDTO> findAll() {
        // 根据创建时间降序排序
        LambdaQueryWrapper<CarriageEntity> queryWrapper = Wrappers.<CarriageEntity>lambdaQuery().orderByDesc(CarriageEntity::getCreated);
        List<CarriageEntity> list = this.list(queryWrapper);
        return list.stream().map(CarriageUtils::toDTO).collect(Collectors.toList());
    }

    @Resource
    CarriageChainHandler carriageChainHandler;

    @Override
    public CarriageDTO compute(WaybillDTO waybillDTO) {
        // 1. 查询运费模版
//        CarriageEntity carriageEntity = findCarriageTemplate(waybillDTO);
        CarriageEntity carriageEntity = carriageChainHandler.findCarriage(waybillDTO);
        // 2. 算出计费重量
        double weight = computeWeight(waybillDTO, carriageEntity);
        // 3. 根据公式计算运费  运费 = 首重价格 + 续重价格 * (计费重量 - 1)
        double expense = carriageEntity.getFirstWeight() + carriageEntity.getContinuousWeight() * (weight - 1);
        expense = NumberUtil.round(expense, 1).doubleValue();
        CarriageDTO carriageDTO = CarriageUtils.toDTO(carriageEntity);
        carriageDTO.setExpense(expense);
        return carriageDTO;
    }

    private double computeWeight(WaybillDTO waybillDTO, CarriageEntity carriageEntity) {
        // 1. 查询体积
        Integer volume = waybillDTO.getVolume();
        if (ObjectUtil.isEmpty(volume)){
            Integer measureLong = waybillDTO.getMeasureLong();
            Integer measureWidth = waybillDTO.getMeasureWidth();
            Integer measureHigh = waybillDTO.getMeasureHigh();
            try {
                volume = measureLong * measureWidth * measureHigh;
            } catch (Exception e) {
                volume = 0;
            }
        }
        // 2. 体积重量 = 体积 / 轻抛系数
        BigDecimal volumeWeight = NumberUtil.div(volume, carriageEntity.getLightThrowingCoefficient());
        // 3. 对比实际重量  和  体积重量  最大值
        double computeWeight = NumberUtil.max(volumeWeight.doubleValue(), waybillDTO.getWeight());

        // 4. 按照需求优化小数点
//        不满1kg，按1kg计费；
        if (computeWeight <= 1){
            return 1;
        }
//        10KG以下：以0.1kg为计重单位，四舍五入保留 1 位小数；
        if (computeWeight < 10){
            return NumberUtil.round(computeWeight, 1).doubleValue();
        }
//        100KG及以上：四舍五入取整；
        if (computeWeight >= 100){
            return NumberUtil.round(computeWeight, 0).doubleValue();
        }
//        10-100KG：续重以0.5kg为计重单位，不足0.5kg按0.5kg算，四舍五入保留 1 位小数；
        // 18.1  --> 18.5    18
        // 18.6  --> 19
        double round = NumberUtil.round(computeWeight, 0, RoundingMode.DOWN).doubleValue();// 向下取整
        double sub = computeWeight - round;
        if (sub < 0.5){
            return NumberUtil.add(round, 0.5);
        }else {
            return NumberUtil.add(round, 1);
        }
    }

    @Resource
    private AreaFeign areaFeign;

    private CarriageEntity findCarriageTemplate(WaybillDTO waybillDTO) {
        // 找模板的顺序:  同城模板  --> 同省  --> 经济区 --> 跨省
        // 1. 找同城模板
        Long senderCityId = waybillDTO.getSenderCityId();
        Long receiverCityId = waybillDTO.getReceiverCityId();
        if (ObjectUtil.equals(senderCityId,receiverCityId)){
            CarriageEntity carriageEntity = findByTemplateType(CarriageConstant.SAME_CITY);
            if (ObjectUtil.isNotEmpty(carriageEntity)){
                return carriageEntity;
            }
        }
        // 2. 找同省模板
        Long senderProvinceId = areaFeign.get(senderCityId).getParentId();
        Long receiverProvinceId = areaFeign.get(receiverCityId).getParentId();
        if (ObjectUtil.equals(senderProvinceId,receiverProvinceId)){
            CarriageEntity carriageEntity = findByTemplateType(CarriageConstant.SAME_PROVINCE);
            if (ObjectUtil.isNotEmpty(carriageEntity)){
                return carriageEntity;
            }
        }
        // 3. 经济区互寄
        CarriageEntity carriageEntity = findByEconomic(senderProvinceId,receiverProvinceId);
        if (ObjectUtil.isNotEmpty(carriageEntity)){
            return carriageEntity;
        }
        // 4. 跨省
        carriageEntity = findByTemplateType(CarriageConstant.TRANS_PROVINCE);
        if (ObjectUtil.isNotEmpty(carriageEntity)){
            return carriageEntity;
        }
        throw new SLException(CarriageExceptionEnum.NOT_FOUND);
    }

    private CarriageEntity findByEconomic(Long senderProvinceId, Long receiverProvinceId) {
        // KEY: BTH      VALUE: 对象(code, [] value)
        LinkedHashMap<String, EconomicRegionEnum> enumMap = EnumUtil.getEnumMap(EconomicRegionEnum.class);
        EconomicRegionEnum economicRegionEnum = null;
        for (EconomicRegionEnum regionEnum : enumMap.values()){
            Long[] value = regionEnum.getValue();
            boolean containsAll = ArrayUtil.containsAll(value, senderProvinceId, receiverProvinceId);
            if (containsAll){
                economicRegionEnum = regionEnum;
                break;
            }
        }
        if (ObjectUtil.isNull(economicRegionEnum)){
            return null;
        }
        CarriageEntity carriageEntity = this.getOne(Wrappers.<CarriageEntity>lambdaQuery()
                .eq(CarriageEntity::getTemplateType, CarriageConstant.ECONOMIC_ZONE)
                .like(CarriageEntity::getAssociatedCity, economicRegionEnum.getCode())
        );
        return carriageEntity;
    }


    public List<CarriageEntity> findByEconomicTemplateType(){
        LambdaQueryWrapper<CarriageEntity> queryWrapper = Wrappers.<CarriageEntity>lambdaQuery()
                .eq(CarriageEntity::getTemplateType, CarriageConstant.ECONOMIC_ZONE);
        return this.list(queryWrapper);
    }


    @Override
    public CarriageEntity findByTemplateType(Integer templateType) {
        if (ObjectUtil.equals(CarriageConstant.ECONOMIC_ZONE, templateType)){
            throw new SLException(CarriageExceptionEnum.TEMPLATE_TYPE_NOT_SUPPORT);
        }
        LambdaQueryWrapper<CarriageEntity> queryWrapper = Wrappers.<CarriageEntity>lambdaQuery()
                .eq(CarriageEntity::getTemplateType, templateType);
        CarriageEntity carriageEntity = this.getOne(queryWrapper);
        return carriageEntity;
    }
}
